package chatroom;

import common.ChatMessage;
import common.Constants;
import common.DataExchange;
import common.Utils;

import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.Executor;
import java.util.concurrent.Executors;


/**
 * @author LinLe
 * @create 2020-12-21 21:09
 */
//聊天的服务器
public class ChatroomServer implements Constants {
    //获取线程池
    private Executor pool = Executors.newCachedThreadPool();
    //存放在线用户的信息
    private Map<String, DataExchange> map = new HashMap<>();
    
    private int port;
    
    public ChatroomServer(int port) {
        this.port = port;
    }
    //开启服务端
    public void start() throws IOException {
        System.out.println("服务器已经启动~~~~~");
        ServerSocket ss = new ServerSocket(SERVER_PORT);
        while(true){
            Socket s = ss.accept();
            //处理客户端的连接请求
            handleClientSocket(s);
        }
    }
    //通过使用线程池来实现多线程
    private void handleClientSocket(Socket s) {
        pool.execute(new ClientHandle(s));
    }
    
    //实现runnable接口
    class ClientHandle implements Runnable{
    
        private Socket s = null;
        //该线程的客户端用户的名字
        private String userName = null;
    
        public ClientHandle(Socket s) {
            this.s = s;
        }
    
        @Override
        public void run() {
            System.out.println("正在处理来自 "+ s.getRemoteSocketAddress() + " 的连接");
            DataExchange de = null;
            try {
                de = new DataExchange(s);
                
            } catch (IOException e) {
                e.printStackTrace();
                return;
            }
            //对于用户名字的初始化
            initUserName(de);
            //注册完毕，开始通信
            while(true) {
                try {
                    ChatMessage receive = de.receive();
                    //获取接受端的名字
                    String toName = receive.getTo();
                    //若是admin，则进行handleServerCommand()方法
                    if (ADMIN_NAME.equalsIgnoreCase(toName)) {
                        //进行退出，或则获取全部在线用户名单的功能
                        handleServerCommand(receive);
                    } else {
                        //就进行一对一聊天
                        handleChatMessage(de, receive, toName);
                    }
                } catch (IOException e) {
                    e.printStackTrace();
                    map.remove(userName).close();
                    return;
                }
            }
    
    
        }
        //就进行一对一聊天
        private void handleChatMessage(DataExchange de, ChatMessage receive, String toName) {
            DataExchange toEx = map.get(toName);
            //判断用户是否存在
            if(toEx == null){
                de.send(new ChatMessage(ADMIN_NAME,receive.getFrom(),toName+"用户不存在"));
            }else{
                //存在就给接收方发送消息
                toEx.send(receive);
            }
        }
        //进行退出，或则获取全部在线用户名单的功能
        private void handleServerCommand(ChatMessage receive) {
            DataExchange from = map.get(receive.getFrom());
            String message = receive.getMessage();
            //若是logoff，则给客户端发送Bye，然后断开通信，并在map集合中除去该用户
            if(SERVER_COMMAND_LOGOFF.equalsIgnoreCase(message)){
                from.send(new ChatMessage(ADMIN_NAME, receive.getFrom(), "Bye"));
                from.close();
                map.remove(userName).close();
                System.out.println(userName+"已离开聊天室");
            }
            //若是list则获取全部在线用户名单
            else if(SERVER_COMMAND_LIST.equalsIgnoreCase(message)){
                from.send(new ChatMessage(ADMIN_NAME, receive.getFrom(),"所有在线用户"+getNames()));
            }
            else{
                from.send(new ChatMessage(ADMIN_NAME, receive.getFrom(),"没有该项指令"));
            }
        }
    
        private String getNames() {
            String userNameListSep = ", ";
            if(map == null){
                //为空就输出原始值@admin
                return CHAT_WITH_START + ADMIN_NAME;
            }else{
                //不为空就通过获取set集合，遍历得到名单
                StringBuilder sb = new StringBuilder(CHAT_WITH_START + ADMIN_NAME);
                Set<String> keySet = map.keySet();
                for (String key: keySet
                     ) {
                    sb.append(userNameListSep+CHAT_WITH_START+key);
                }
                return sb.toString();
            }
        }
    
        private void initUserName(DataExchange de) {
            //用户名正确与否
            String errorMsg = null;
            while(true){
                //获取map里的全部在线用户名单
                String allName = getNames();
                de.send(new ChatMessage(ADMIN_NAME,NO_NAME,(errorMsg == null ? "" :
                        "用户名非法,错误信息是: " + errorMsg+ ":")+ "目前在线用户名有：" +
                        allName + "。请输入你的用户名："));
                try {
                    ChatMessage chatMessage = de.receive();
                    //客户端用户首次注册的名字
                    String name = chatMessage.getMessage();
                    //判断该名字是否合法
                    errorMsg = Utils.isValidUserName(name);
                    //判断该名字是否已存在
                    if(errorMsg == null && (!map.containsKey(name)) ){
                        this.userName = name;
                        map.put(userName,de);
                        de.send(new ChatMessage(ADMIN_NAME,name,USER_NAME_PASS));
                        //表示注册成功，给客户端发送成功消息
                        de.send(new ChatMessage(ADMIN_NAME,name,COMMAND_INTRODUCTION));
                        return;
                    }
    
                } catch (IOException e) {
                    e.printStackTrace();
                    de.close();
                    return;
                }
    
            }
            
            
            
        }
        
    }
    
}
